import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.intellij.openapi.ui.Messages
import java.awt.Toolkit
import java.awt.datatransfer.DataFlavor
import java.io.File


fun main() {
    val pojoGen = PojoGen()
    pojoGen.gen(File("/Users/jerry/projects/mine/gitee/demos/pluginDemo/modifyTextPluginDemo/123"))
}

class PojoGen {
    var classList = mutableListOf<List<String>>()
    var newLine = "\n"
    fun gen(baseFile: File): File? {
        val clipboard = Toolkit.getDefaultToolkit().systemClipboard
        val text = clipboard.getData(DataFlavor.stringFlavor)
        if (text == null || text.toString().isNullOrEmpty()) {
            Messages.showMessageDialog("请先复制yapi上RAW数据", "使用提示", Messages.getInformationIcon())
            return null
        }
        try {
            val jsonObject = JSON.parse(text.toString()) as JSONObject
            processJsonObj1("PojoClass", jsonObject)
            return saveToFile(baseFile)
        } catch (e: Exception) {
            Messages.showMessageDialog("剪贴板内容格式错误", "错误提示", Messages.getErrorIcon())
            return null
        }
    }

    private fun saveToFile(file: File): File {
        var fileName = "YapiPojo.kt"
        var resultFile: File
        resultFile = if (file.isDirectory) {
            File(file, fileName)
        } else {
            File(file.parentFile, fileName)
        }
        var stringBuilder = StringBuilder()
        stringBuilder.append("import java.io.Serializable$newLine")
        classList.forEach {
            stringBuilder.append(it.joinToString(separator = newLine))
        }
        resultFile.writeText(stringBuilder.toString())
        return resultFile
    }

    private fun processJsonObj1(name: String, jsonObject: JSONObject) {
        var codeLineList = mutableListOf<String>()
        classList.add(codeLineList)
        val props = jsonObject["properties"] as JSONObject
        codeLineList.add("data class " + convertType(name) + "(")
        props.forEach {
            processJsonObj2(it.key, it.value as JSONObject, codeLineList)
        }
        replaceLastComma(codeLineList)
        codeLineList.add("): Serializable$newLine")
    }

    /**
     * 删除最后一行属性定义后面的逗号
     */
    private fun replaceLastComma(codeLineList: MutableList<String>) {
        val lastItem = codeLineList.last()
        if (lastItem.endsWith(",")) {
            codeLineList.removeAt(codeLineList.lastIndex)
            codeLineList.add(lastItem.replace(",", ""))
        }
    }

    private fun processJsonObj2(originalPropName: String, jsonObject: JSONObject, codeLineList: MutableList<String>) {
        val type = getObjType(jsonObject)
        if (type == "object") {
            var newTypeName = NameMan.getNewClassName(originalPropName)
            addProp(originalPropName, newTypeName, jsonObject["description"], codeLineList, getRawTypeDefaultValue(type))
            processJsonObj1(newTypeName, jsonObject)
        } else if (type == "array") {
            val jsonObjectForArray = jsonObject["items"] as JSONObject
            val subType = jsonObjectForArray["type"].toString()
            val isRawType = isRawType(subType)
            if (isRawType) {
                addProp(originalPropName, convertType(type, subType), jsonObject["description"], codeLineList)
            } else {
                var newTypeName = NameMan.getNewClassName(originalPropName)
                addProp(originalPropName, convertType(type, newTypeName), jsonObject["description"], codeLineList)
                processJsonObj1(newTypeName, jsonObjectForArray)
            }
        } else {
            addProp(originalPropName, convertType(type), jsonObject["description"], codeLineList, getRawTypeDefaultValue(type))
        }
    }

    private fun addProp(propName: String, propType: String, description: Any?, codeLineList: MutableList<String>, rawTypeDefaultValue: String? = null) {
        description?.let {
            codeLineList.add("/**")
            codeLineList.add("* " + it.toString().replace("\n", " "))
            codeLineList.add("*/")
        }
        if (rawTypeDefaultValue != null) {
            codeLineList.add("var $propName: $propType=$rawTypeDefaultValue,")
        } else {
            codeLineList.add("var $propName: $propType?=null,")
        }
    }

    private fun convertType(type: String, subType: String? = null): String {
        return when (type) {
            "number" -> "Long"
            "array" -> "List<" + convertType(subType!!) + ">"
            else -> type.capitalize()
        }
    }

    private fun getObjType(jsonObject: JSONObject): String {
        return jsonObject["type"].toString()
    }

    private fun isRawType(type: String): Boolean {
        val list = listOf("string", "number", "boolean", "integer")
        return list.contains(type)
    }

    private fun getRawTypeDefaultValue(type: String): String? {
        when (type) {
            "string" -> return "\"\""
            "number" -> return "0"
            "integer" -> return "0"
            "boolean" -> return "false"
        }
        return null
    }

    object NameMan {
        fun getNewClassName(name: String): String {
            var result = if (isConflictWithKeywords(name)) {
                getRandomName()
            } else {
                name
            }
            return result.capitalize()
        }

        private fun isConflictWithKeywords(name: String): Boolean {
            val list = listOf("list", "map")
            return list.contains(name)
        }

        var nameIndex = 1
        private fun getRandomName(): String {
            var name = "Obj$nameIndex"
            nameIndex++
            return name
        }
    }
}